import sys
import os
import socket
import struct
import json
import threading
import time
OPEN_CAMERA_COMMAND = b'\xff\xff\xff\xff\x19\x00\x00\x00\x0a\x00\x00\x00\x7b\x22\x73\x74\x61\x74\x75\x73\x22\x3a\x20\x30\x7d'
BACKUP_COMMAND = b'\xff\xff\xff\xff\x19\x00\x00\x00\x08\x00\x00\x00\x7b\x22\x73\x74\x61\x74\x75\x73\x22\x3a\x20\x30\x7d'

os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = './platforms'

from PySide2.QtWidgets import QApplication, QWidget
from PySide2.QtCore import QFile, Signal
from PySide2.QtUiTools import QUiLoader

socket.setdefaulttimeout(30)
DEBUG = True
STORE_PATH = os.path.join(os.getcwd(), 'store')
close_command = False
upload_status = False
total = 0
progress = 0
HEAD_SIGNAL = bytearray(b'\xff\xaa\xff\xaa')

class Main(QWidget):
    signal_thread_start = Signal(str)
    signal_progress = Signal(int)
    signal_upload_status = Signal(str)
    signal_history = Signal(str)
    signal_single_upload = Signal(str)
    def __init__(self):
        super(Main, self).__init__()
        self.load_ui()
        res = os.path.exists(STORE_PATH)
        if not res:
            os.makedirs(STORE_PATH)

    def __del__(self):
        global close_command
        close_command = True
        print('关闭', close_command)

    def load_ui(self):
        loader = QUiLoader()
        path = "./form.ui"
        ui_file = QFile(path)
        ui_file.open(QFile.ReadOnly)
        self.ui = loader.load(ui_file, self)
        ui_file.close()
        self.ip = str(socket.gethostbyname(socket.gethostname()))
        self.ui.ipBox.setText(self.ip)


    def widget_setting(self):
        self.ui.startServerButton.clicked.connect(self.start_server_thread)
        self.ui.closeServerButton.clicked.connect(self.stop_server)
        self.ui.openFileManagerButton.clicked.connect(self.open_store)
        self.signal_thread_start.connect(self.update_status)
        self.signal_progress.connect(self.set_progress)
        self.signal_upload_status.connect(self.update_upload_status)
        self.signal_history.connect(self.update_history)
        self.signal_single_upload.connect(self.update_single_upload)
        self.ui.open_camera_button.clicked.connect(self.start_nano_camera)
        self.ui.backup_button.clicked.connect(self.start_nano_backup)

    def update_single_upload(self, string):
        self.ui.uploadProgressLabel.setText(string)

    def get_localtime(self):
        return str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

    def update_history(self, string):
        self.ui.historyBox.insertPlainText(string)

    def update_upload_status(self, string):
        self.ui.uploadStatusLabel.setText(string)

    def open_store(self):
        res = os.path.exists(STORE_PATH)
        if not res:
            os.makedirs(STORE_PATH)
        os.startfile(STORE_PATH)

    def set_progress(self, value):
        self.ui.progressBar.setValue(value)

    def update_status(self, string):
        self.ui.label_2.setText(string)

    def stop_server(self):
        global close_command
        close_command = True
        self.signal_thread_start.emit('关闭中...请等待10秒')
        self.ui.startServerButton.setEnabled(True)


    def start_server_thread(self):
        thread = threading.Thread(target=self.server_thread)
        thread.start()
        self.ui.startServerButton.setEnabled(False)

    def start_nano_backup(self):
        thread = threading.Thread(target=self.send_command_thread, args=2)
        thread.start()

    def start_nano_camera(self):
        thread = threading.Thread(target=self.send_command_thread, args=1)
        thread.start()

    def send_command_thread(self, type):
        try:
            nano_ip = self.ui.ipBox2.toPlainText()
            nano_port = self.ui.portBox.toPlainText()
            sk = socket.socket()
            sk.connect((nano_ip, int(nano_port)))
            if type == 1:
                length = len(OPEN_CAMERA_COMMAND) + 8
                length = length.to_bytes(4, byteorder='little')
                sk.sendall(b'\xff\xff\xff\xff' + length + OPEN_CAMERA_COMMAND)
            elif type == 2:
                length = len(BACKUP_COMMAND) + 8
                length = length.to_bytes(4, byteorder='little')
                sk.sendall(b'\xff\xff\xff\xff' + length + BACKUP_COMMAND)
            sk.close()
        except:
            import traceback
            traceback.print_exc()


    def server_thread(self):
        global upload_status, total, progress
        sk = socket.socket()
        sk.bind((self.ip, 60008))  # 绑定ip地址和端口
        sk.listen()  # 开启监听
        self.signal_thread_start.emit("开启")
        print("服务端开启")
        buffer = 1024  # 缓冲区大小，这里好像因为windows的系统的原因，这个接收的缓冲区不能太大
        while True:
            try:
                if close_command:
                    break
                conn, addr = sk.accept()
                print(addr, " connected")
                while True:
                    try:
                        if close_command:
                            break
                        # 接收单个文件的头部数据
                        head_str = conn.recv(8)
                        data = bytearray(head_str)
                        # 查找间隔符在数据中的index，4 bits
                        headIndex = data.find(b'\xff\xaa\xff\xaa')
                        # 获取json部分的长度
                        json_len = int.from_bytes(data[headIndex + 4: headIndex + 8], byteorder='little')
                        print("json_len:", json_len)
                        # 接收json数据，并拼接到同一个数据包
                        data += conn.recv(json_len)
                        # 截取json部分的数据包
                        print("data:", data)
                        json_str = data[headIndex + 8: headIndex + 8 + json_len].decode('utf-8')
                        # if len(json_str) == 0:
                        #     break
                        # print("data:", data)
                        # 字符串转json 对象
                        json_obj = json.loads(json_str)
                        if not upload_status:
                            upload_status = True
                            total = int(json_obj['l'])
                            self.signal_upload_status.emit("是")
                            localtime = self.get_localtime()
                            content = localtime + ' 上传文件' + str(total) + '个\n'
                            self.signal_history.emit(content)
                        # 读取文件长度字段filesize的值
                        filesize = json_obj['filesize']
                        print("文件尺寸:", filesize)
                        save_path = STORE_PATH + json_obj['filepath']
                        self.signal_history.emit("正在接收文件:" + save_path)
                        if not os.path.exists(save_path):
                            os.makedirs(save_path)
                        save_file_path = os.path.join(save_path, json_obj['filename'])
                        current_size = 0
                        ret_num = 0
                        ret_data = HEAD_SIGNAL + ret_num.to_bytes(4, byteorder='little')
                        conn.sendall(ret_data)
                        if os.path.exists(save_file_path):
                            os.remove(save_file_path)
                        with open(save_file_path, 'ab') as f:
                            # 开始数据接收循环
                            while filesize > 0:
                                # 接收数据头
                                sub_head_str = conn.recv(buffer)
                                sub_data = bytearray(sub_head_str)
                                headIndex = sub_data.find(b'\xff\xaa\xff\xaa')
                                data_len = int.from_bytes(sub_data[headIndex + 4: headIndex + 8], byteorder='little')
                                # print(headIndex, ":", data_len)
                                # print(len(sub_data), data_len + 8)
                                if len(sub_data) == (data_len + 8):
                                    print("success")
                                    file_data = sub_data[headIndex + 8: headIndex + 8 + data_len]
                                    filesize -= data_len
                                    current_size += data_len
                                    f.write(file_data)
                                    package_ready_content = '0'
                                    package_ready_content = package_ready_content.encode('utf-8')
                                    conn.sendall(package_ready_content)
                                else:
                                    print(filesize)
                                    print(len(sub_data), data_len)
                                    print("fail")
                                    package_ready_content = '1'
                                    package_ready_content = package_ready_content.encode('utf-8')
                                    conn.sendall(package_ready_content)
                                    continue
                                self.signal_single_upload.emit(str(json_obj['filesize']) + '/' + str(current_size))
                        f.close()
                        print("current_size:", current_size)
                        print("传输结束")
                        size = os.path.getsize(save_file_path)
                        ready_content = '1'
                        if int(size) == int(json_obj['filesize']):
                            self.signal_history.emit(save_file_path + " 文件完整度检验正确\n")
                            ready_content = '0'
                            ready_content = ready_content.encode('utf-8')
                        else:
                            self.signal_history.emit(save_file_path + " 文件完整度检验错误！！！！\n")
                            ready_content = ready_content.encode('utf-8')
                        conn.sendall(ready_content)
                        # ready_content = str(rec_status['status'])
                        #     ready_content = ready_content.encode('utf-8')
                        #     conn.sendall(ready_content)
                        # rec_status['status'] = 1
                        # ----- new -----
                        # # 再接收报头
                        # json_head = conn.recv(head_len).decode('utf-8')
                        # head = json.loads(json_head)  # 拿到原本的报头
                        # print(head)
                        # if not upload_status:
                        #     upload_status = True
                        #     total = int(head['l'])
                        #     self.signal_upload_status.emit("是")
                        #     localtime = self.get_localtime()
                        #     content = localtime + ' 上传文件' + str(total) + '个\n'
                        #     self.signal_history.emit(content)
                        # file_size = head['filesize']
                        # save_path = STORE_PATH + head['filepath']
                        # # print(save_path)
                        # if not os.path.exists(save_path):
                        #     os.makedirs(save_path)
                        # save_file_path = os.path.join(save_path, head['filename'])
                        # if os.path.exists(save_file_path):
                        #     os.remove(save_file_path)
                        # with open(save_file_path, 'ab') as f:
                        #     localtime = self.get_localtime()
                        #     content = localtime + " 开始传输文件" + save_file_path + '\n'
                        #     progress_str = str(file_size) + '/0'
                        #     self.signal_single_upload.emit(progress_str)
                        #     self.signal_history.emit(content)
                        #     current_file_size = 0
                        #     rec_status = {"status": 0}
                        #     while file_size:
                        #         if file_size >= buffer:  # 判断剩余文件的大小是否超过buffer
                        #             content = conn.recv(buffer)
                        #             f.write(content)
                        #             file_size -= buffer
                        #             current_file_size += buffer
                        #             self.signal_single_upload.emit(str(head['filesize']) + '/' + str(current_file_size))
                        #         else:
                        #             content = conn.recv(file_size)
                        #             f.write(content)
                        #             f.close()
                        #             size = os.path.getsize(save_file_path)
                        #             # current_file_size = 0
                        #             self.signal_single_upload.emit(str(head['filesize']) + '/' + str(head['filesize']))
                        #             if int(size) == int(head['filesize']):
                        #                 self.signal_history.emit(save_file_path + " 文件完整度检验正确\n")
                        #             else:
                        #                 self.signal_history.emit(save_file_path + " 文件完整度检验错误！！！！\n")
                        #                 rec_status['status'] = 1
                        #             break
                        #     ready_content = str(rec_status['status'])
                        #     ready_content = ready_content.encode('utf-8')
                        #     conn.sendall(ready_content)
                        #
                        if upload_status:
                            progress += 1
                            value = int(progress/total * 100)
                            self.signal_progress.emit(value)
                            if progress == total:
                                upload_status = False
                                self.signal_progress.emit(0)
                                self.signal_single_upload.emit('0/0')
                                progress = 0
                                total = 0
                                self.signal_upload_status.emit("否")
                                localtime = self.get_localtime()
                                content = localtime + ' 上传文件完成\n'
                                self.signal_history.emit(content)
                        # # conn.close()
                    except Exception:
                        if DEBUG:
                            import traceback
                            traceback.print_exc()
                        # print('close')
                        conn.close()
                        break
            except Exception:
                if DEBUG:
                    import traceback
                    traceback.print_exc()
                # print('continue')
                continue
        sk.close()
        self.signal_thread_start.emit("关闭")
        print("服务端线程结束")


if __name__ == "__main__":
    app = QApplication([])
    widget = Main()
    widget.setWindowTitle("采集文件上传服务端")
    widget.widget_setting()
    widget.show()
    sys.exit(app.exec_())
